#include <bolt.h>
#include <prot.h>
#include "basic.h"

BOLT(gt_release, "gtool <id> release")
{
   uint32_t id;
   if (str2u32(pop_argz(), &id)){
      gtool_release((int)id);
   }
}

BOLT(gt_send, "gtool <id> send <number>")
{
   uint32_t num, id;
   int ret;
   
   if (!str2u32(pop_argz(), &num)){
      printf("invalid number\n");
      return;
   } 
   if (!str2u32(pop_argz(), &id)){
      printf("invalid id\n");
      return;
   } 
   for (ret=0;num>0;num--){
      if (gtool_send((int)id) > 0) 
         ret++;
      usleep(1);
   }
         
   printf("gtool send num=%d\n", ret);
}

BOLT(gt_user_ip_addr, "gtool <id> user ip address <src-ip> <dst-ip>")
{
   uint32_t gt_id, src_ip, dst_ip;
   
   if (!ip2u32(pop_argz(), &dst_ip)){
      printf ("Invalid destination IP.\n");
      return;
   }
   if (!ip2u32(pop_argz(), &src_ip)) {
      printf ("Invalid source IP.\n");
      return;
   }
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_ip_addr(gt_id, src_ip, dst_ip) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_udp, "gtool <id> user udp port <source> <dest>")
{
   uint32_t gt_id;
   uint16_t src_port, dst_port;
   
   if (!str2u16(pop_argz(), &dst_port)){
      printf("invalid destination port\n");
      return;
   } 
   if (!str2u16(pop_argz(), &src_port)){
      printf("invalid source port\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_udp_port((int)gt_id, src_port, dst_port) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_ip_p, "gtool <id> user ip ip-protocol <ip-p>")
{
   uint32_t gt_id;
   uint8_t p;
   if (!str2u8(pop_argz(), &p)){
      printf("Invalid IP protocol.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_ip_prot(gt_id, p) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_ip_tos, "gtool <id> user ip ip-tos <ip-tos>")
{
   uint32_t gt_id;
   uint8_t ip_tos;
   if (!str2u8(pop_argz(), &ip_tos)){
      printf("Invalid IP TOS.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_ip_tos(gt_id, ip_tos) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_ip_id, "gtool <id> user ip ip-id <ip-id>")
{
   uint32_t gt_id;
   uint16_t ip_id;
   if (!str2u16(pop_argz(), &ip_id)){
      printf("Invalid IP identifier.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_ip_id(gt_id, ip_id) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_ip_off, "gtool <id> user ip ipoff <ipoff>")
{
   uint32_t gt_id;
   uint16_t ip_off;
   if (!str2u16(pop_argz(), &ip_off)){
      printf("Invalid IP offset.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_ip_off(gt_id, ip_off) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_ip_ttl, "gtool <id> user ip ttl <ttl>")
{
   uint32_t gt_id;
   uint8_t ip_ttl;
   if (!str2u8(pop_argz(), &ip_ttl)){
      printf("Invalid IP TTL.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_ip_ttl(gt_id, ip_ttl) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_icmp_code, "gtool <id> user icmp type <type> code <code>")
{
   uint32_t gt_id;
   uint8_t type,code;
   if (!str2u8(pop_argz(), &code)){
      printf("Invalid ICMP code.\n");
      return;
   }
   if (!str2u8(pop_argz(), &type)){
      printf("Invalid ICMP type.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_icmp_type(gt_id, type, code) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_icmp_chksum, "gtool <id> user icmp chksum <chksum>")
{
   uint32_t gt_id;
   uint16_t chksum;
   if (!str2u16(pop_argz(), &chksum)){
      printf("Invalid ICMP checksum.\n");
      return;
   }
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_icmp_chksum(gt_id, chksum) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_icmp_echo_seq, "gtool <id> user icmp echo <id> <seq>")
{
   uint32_t gt_id;
   uint16_t id,sequence;
   if (!str2u16(pop_argz(), &sequence)){
      printf("Invalid ICMP sequence.\n");
      return;
   }
   if (!str2u16(pop_argz(), &id)){
      printf("Invalid ICMP id.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_icmp_echo(gt_id, id, sequence) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_icmp_gateway, "gtool <id> user icmp gateway <ip-addr>")
{
   uint32_t gt_id;
   uint32_t gateway;

   if (!ip2u32(pop_argz(), &gateway)) {
      printf ("Invalid gateway\n");
      return;  
   }
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_icmp_gateway(gt_id, gateway) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_icmp_mtu, "gtool <id> user icmp mtu <mtu>")
{
   uint32_t gt_id;
   uint16_t mtu;

   if (!str2u16(pop_argz(), &mtu)){
      printf("Invalid ICMP mtu.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_icmp_mtu(gt_id, mtu) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_tcp_port, "gtool <id> user tcp port <source> <dest>")
{
   uint32_t gt_id;
   uint16_t source,dest;
   if (!str2u16(pop_argz(), &dest)){
      printf("Invalid TCP dest.\n");
      return;
   }
   if (!str2u16(pop_argz(), &source)){
      printf("Invalid TCP source.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_tcp_port(gt_id, source, dest) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_tcp, "gtool <id> user tcp seq <seq> <ack-seq>")
{
   uint32_t gt_id;
   uint32_t seq,ack;
   if (!str2u32(pop_argz(), &ack)){
      printf("Invalid TCP ack sequence.\n");
      return;
   }
   if (!str2u32(pop_argz(), &seq)){
      printf("Invalid TCP sequence.\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_tcp_seq(gt_id, seq, ack) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_tcp_offx2, "gtool <id> user tcp offx2 <offx2>")
{
   uint32_t gt_id;
   uint8_t offx2;
   if (!str2u8(pop_argz(), &offx2)){
      printf("Invalid TCP offx2.\n");
      return;
   }
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_tcp_offx2(gt_id, offx2) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_tcp_flags, "gtool <id> user tcp flags <flags>")
{
   uint32_t gt_id;
   uint8_t flags;
   if (!str2u8(pop_argz(), &flags)){
      printf("Invalid TCP offx2.\n");
      return;
   }
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_tcp_flags(gt_id, flags) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_tcp_wins, "gtool <id> user tcp windows <windows>")
{
   uint32_t gt_id;
   uint16_t windows;
   if (!str2u16(pop_argz(), &windows)){
      printf("Invalid TCP windows.\n");
      return;
   }
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_tcp_windows(gt_id, windows) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_tcp_check, "gtool <id> user tcp check <check>")
{
   uint32_t gt_id;
   uint16_t check;
   if (!str2u16(pop_argz(), &check)){
      printf("Invalid TCP check.\n");
      return;
   }
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_tcp_check(gt_id, check) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_tcp_urg, "gtool <id> user tcp urg_ptr <urg_ptr>")
{
   uint32_t gt_id;
   uint16_t urg_ptr;
   if (!str2u16(pop_argz(), &urg_ptr)){
      printf("Invalid TCP urg ptr.\n");
      return;
   }
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   if (gtool_user_tcp_urg_ptr(gt_id, urg_ptr) == 0)
      printf("OK.\n");
   else
      printf("Failure.\n");
}

BOLT(gt_user_sicp, "gtool <id> user sicp")
{
    uint32_t gt_id;

    if (!str2u32(pop_argz(), &gt_id)){
       printf("invalid id\n");
       return;
    }
    if (gtool_user_sicp((int)gt_id) == 0)
       printf ("Set sicp payload successfully.\n");
    else
       printf ("Set sicp payload failure.\n");
}

BOLT(gt_user_show, "gtool <id> user show")
{
   uint32_t gt_id;

   if (!str2u32(pop_argz(), &gt_id) 
      || gtool_user_show((int)gt_id) != 0)
      printf("No such gtool.\n");
}

BOLT(gt_show, "gtool show")
{
   gtool_show();
}

BOLT(gt_create, "gtool <id> create <src-ip> <src-port> <src-teid> <dst-ip> <dst-port> <dst-teid>")
{
   int id;
   sockaddr_t src, dst;
   uint32_t gt_id, src_teid,dst_teid;
   uint16_t port;
   
   memset(&src, 0, sizeof(src));
   memset(&dst, 0, sizeof(dst));
   
   if (!str2u32(pop_argz(), &dst_teid)){
      printf("invalid destination teid\n");
      return;
   } 
   if (!str2u16(pop_argz(), &port)){
      printf("invalid destination port\n");
      return;
   } 
   if (!ip2addr(pop_argz(), &dst.v0)) {
      printf ("Invalid destination IP\n");
      return;
   }
   addr_set_port(&dst, port);
   if (!str2u32(pop_argz(), &src_teid)){
      printf("invalid source teid\n");
      return;
   } 
   if (!str2u16(pop_argz(), &port)){
      printf("invalid source port\n");
      return;
   } 
   if (!ip2addr(pop_argz(), &src.v0)) {
      printf ("Invalid source IP.\n");
      return;
   }
   addr_set_port(&src, port);
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   }
   id = gtool_create((int)gt_id, &src, src_teid, &dst, dst_teid);
   printf("The gtool id is %d\n", id);
}

BOLT(gt_rate, "gtool <id> rate <rate>")
{
   uint32_t gt_id, rate;

   if (!str2u32(pop_argz(), &rate)){
      printf("invalid rate limit\n");
      return;
   } 
   if (!str2u32(pop_argz(), &gt_id)){
      printf("invalid id\n");
      return;
   } 
   gtool_rate((int)gt_id, rate);
}

BOLT(gt_dscp, "gtool <id> dscp <dscp>")
{
   uint8_t dscp = 0;
   uint32_t gt_id;
   
   const char *argz = pop_argz();
   if (argz == NULL || !str2u8(argz, &dscp)){
      printf("invalid DSCP\n");
      return;
   }
   if (dscp < 0 || dscp > 63) {
       printf("invalid DSCP, range[0~63]\n");
       return;
   }    
   argz = pop_argz();
   if (argz == NULL || !str2u32(argz, &gt_id)){
      printf("invalid ID\n");
      return;
   }
   if (gtool_set_dscp((int)gt_id, dscp) == 0)
      printf ("Set dscp successfully.\n");
   else
      printf ("Set dscp failure.\n");
}

static void __gtool_profile(void *desc, void *gt)
{
   char srcstr[IP_ADDR_STR_LEN], dststr[IP_ADDR_STR_LEN];
   sockaddr_t srcaddr, dstaddr;
   gtool_get_src_addr(gt, &srcaddr);
   gtool_get_dst_addr(gt, &dstaddr);
   cmd_load_profile(desc, "gtool %u create %s %u 0x%x %s %u 0x%x\n", 
      gtool_get_id(gt),
      ipstr4addr(&srcaddr.v0, srcstr, sizeof(srcstr)),
      port4addr(&srcaddr.v0),
      gtool_get_src_teid(gt),
      ipstr4addr(&dstaddr.v0, dststr, sizeof(dststr)),
      port4addr(&dstaddr.v0),
      gtool_get_dst_teid(gt));   
}

static void __gtool_dscp_profile(void *desc, void *gt)
{
   if (gtool_get_dscp(gt) != 0xff)
      cmd_load_profile(desc, "gtool %u dscp %u\n", 
         gtool_get_id(gt), gtool_get_dscp(gt));  
}

BOLT_PROFILE(gtool, "", cmd_gtool_profile, desc)
{
   void *gt;
   for (gt = gtool_first(); gt != NULL; gt = gtool_next(gt)) {
      __gtool_profile(desc, gt);
      __gtool_dscp_profile(desc, gt);
      cmd_load_profile(desc, "\n");
   }
}

